# 函数

"""
定义一个函数：
1.函数代码块以 def 关键字开头，后接函数标识符名称和圆括号()
2.任何传入参数和自变量必须放在圆括号中间，圆括号之间可以用于定义参数
3.函数第一行语句可以选择性的使用文档字符串--用于存放函数说明
4.函数内容以冒号其实，并且缩进
5. return[表达式]结束函数，选择性的返回一个值给调用方，不带代表式的return相当于返回None

语法：

def 函数名（参数列表）：
    函数体

"""


def hello():
    print("你好！")


for a in range(9):
    hello()


def welcome(name):
    print("Welcome ", name)


welcome("晴天")


def ara(w, h):
    return w * h


w = 10
h = 5
s = ara(w, h)
print("面积为：", s)

"""
python 函数传递参数：

不可变类型：
类似 c++ 的值传递，如 整数、字符串、元组。如fun（a），
传递的只是a的值，没有影响a对象本身。比如在 fun（a）内部修改 a 的值，
只是修改另一个复制的对象，不会影响 a 本身。


可变类型：
类似 c++ 的引用传递，如 列表，字典。如 fun（la），
则是将 la 真正的传过去，修改后fun外部的la也会受影响
"""

"""
参数

以下是调用函数时可使用的正式参数类型：
必需参数
关键字参数
默认参数
不定长参数
"""

"""
必需参数
必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用 printme() 函数，你必须传入一个参数，不然会出现语法错误：
"""

"""
关键字参数
关键字参数和函数调用关系紧密，函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致，
因为 Python 解释器能够用参数名匹配参数值。
"""

"""
默认参数
调用函数时，如果没有传递参数，则会使用默认参数。
"""

"""
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。
这些参数叫做不定长参数，和上述 2 种参数不同，声明时不会命名。

1.加了星号 * 的参数会以元组(tuple)的形式导入，存放所有未命名的变量参数。
2.如果在函数调用时没有指定参数，它就是一个空元组。我们也可以不向函数传递未命名的变量。
3.加了两个星号 ** 的参数会以字典的形式导入。
4.声明函数时，参数中星号 * 可以单独出现
"""

"""
匿名函数
python 使用 lambda 来创建匿名函数。

所谓匿名，意即不再使用 def 语句这样标准的形式定义一个函数。

lambda 只是一个表达式，函数体比 def 简单很多。
lambda的主体是一个表达式，而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
lambda 函数拥有自己的命名空间，且不能访问自己参数列表之外或全局命名空间里的参数。
虽然lambda函数看起来只能写一行，却不等同于C或C++的内联函数，后者的目的是调用小函数时不占用栈内存从而增加运行效率。

lambda函数的语法只包含一个语句：
lambda [arg1[,arg2,...argn]]:expression
"""

sum = lambda arg1, arg2: arg1 + arg2

print("776+1=", sum(1, 776))

"""
return [表达式] 语句用于退出函数，
选择性地向调用方返回一个表达式。
不带参数值的return语句返回None。
"""


def sum(a, b):
    total = a + b
    print("a+b=", total)
    return total


total = sum(10, 20)
print("total=", total)

"""
变量作用域:
Python 中，程序的变量并不是在哪个位置都可以访问的，
访问权限决定于这个变量是在哪里赋值的。

变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种，分别是：

L （Local） 局部作用域
E （Enclosing） 闭包函数外的函数中
G （Global） 全局作用域
B （Built-in） 内置作用域（内置函数所在模块的范围）
以 L –> E –> G –>B 的规则查找，即：在局部找不到，便会去局部外的局部找（例如闭包），再找不到就会去全局找，再者去内置中找。
"""

# 全局作用域
g_count = 0
def outer():
    # 闭包函数外的函数中
    o_count = 1
    def inner():
        # 局部作用域
        i_count = 2



"""
内置作用域是通过一个名为 builtin 的标准模块来实现的，
但是这个变量名自身并没有放入内置作用域内，
所以必须导入这个文件才能够使用它。
"""

import builtins
dir(builtins)

"""
Python 中只有模块（module），类（class）以及函数（def、lambda）才会引入新的作用域，
其它的代码块（如 if/elif/else/、try/except、for/while等）是不会引入新的作用域的，
也就是说这些语句内定义的变量，外部也可以访问，
"""


"""
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域，定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问，而全局变量可以在整个程序范围内访问。
调用函数时，所有在函数内声明的变量名称都将被加入到作用域中。
"""

"""
global 和 nonlocal关键字
当内部作用域想修改外部作用域的变量时，就要用到global和nonlocal关键字了。

如果要修改嵌套作用域（enclosing 作用域，外层非全局作用域）中的变量则需要 nonlocal 关键字

"""

num=1
def fun1():
    global num
    num=777777
fun1()
print(num)

